#include "ET++.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "Buttons.h"

#include "Class.h"
#include "TextItem.h"
#include "WindowSystem.h"
#include "Look.h"

bool gInButtonFlush;

//---- Button ------------------------------------------------------------------

NewAbstractMetaImpl0(Button,CompositeVObject);

Button::Button(int id, VObject *vop) : CompositeVObject(id, vop, 0)
{
}

Command *Button::DoLeftButtonDownCommand(Point, Token, int)
{
	return new ButtonCommand(this, TestFlag(eButtonIdle));
}

void Button::Flush(int msec)
{
	if (Enabled()) {
		gInButtonFlush= TRUE;
		DoTrackMouse(eTrackPress, contentRect.Center());
		GraphicDelay(msec);
		DoTrackMouse(eTrackRelease, contentRect.Center());
		gInButtonFlush= FALSE;
	}
}

void Button::DoTrackMouse(TrackPhase atp, Point lp)
{
	if (Enabled() && TestFlag(eButtonIdle)) {
		switch (atp) {
		case eTrackPress:
			Highlight(On);
		case eTrackMove:
		case eTrackIdle:
			Control(GetId(), cPartToggle, (void*) 1);
			break;
		case eTrackRelease:
		case eTrackExit:
			Highlight(Off);
			break;
		default:
			break;
		}
	} else
		CompositeVObject::DoTrackMouse(atp, lp);
}

void Button::DrawHighlight(Rectangle)
{
}

void Button::SetOrigin(Point at)
{
	VObject::SetOrigin(at);
	if (Size() > 0)
		At(0)->Align(at, GetExtent(), (VObjAlign)(eVObjHCenter|eVObjVCenter));
}

void Button::SetLabel(const char *lb, bool redraw)
{
	if (At(0)->IsKindOf(TextItem)) {
		TextItem *ti= (TextItem*) At(0);
		ti->SetString(lb);
		SetOrigin(GetOrigin());
		if (redraw)
			ForceRedraw();
	}
}

Metric Button::GetMinSize()
{
	return CompositeVObject::GetMinSize();
}

//---- ButtonCommand -----------------------------------------------------------

ButtonCommand::ButtonCommand(Button* bf, bool idl)
{
	item= bf;
	lastinside= FALSE;
	SetFlag(eCmdIdleEvents, idl);
}

void ButtonCommand::TrackFeedback(Point, Point, bool)
{
}

Command *ButtonCommand::TrackMouse(TrackPhase atp, Point, Point, Point np)
{
	inside= item->ContainsPoint(np);
	switch(atp) {
	case eTrackPress:
		if (inside)
			item->DoTrackMouse(eTrackPress, np);
		break;
	case eTrackIdle:
		if (inside)
			item->DoTrackMouse(eTrackIdle, np);
		break;
	case eTrackExit:
		item->DoTrackMouse(eTrackExit, np);
		break;
	case eTrackRelease:
		if (inside)
			item->DoTrackMouse(eTrackRelease, np);
		else
			item->DoTrackMouse(eTrackExit, np);
		return gNoChanges;
	case eTrackMove:
		if (lastinside && !inside)
			item->DoTrackMouse(eTrackExit, np);
		else if (!lastinside && inside)
			item->DoTrackMouse(eTrackPress, np);
		else if (inside)
			item->DoTrackMouse(eTrackMove, np);
		break;
	}
	lastinside= inside;
	return this;
}

//---- ActionButton ------------------------------------------------------------

NewMetaImpl0(ActionButton,Button);

ActionButton::ActionButton(int id, VObject *g, bool dflt) : Button(id, g)
{
	SetFlag(eActionDefaultButton, dflt);
	SetFlag(eVObjVFixed);
}

ActionButton::ActionButton(int id, const char *t, bool dflt)
										: Button(id, new TextItem(t))
{
	SetFlag(eActionDefaultButton, dflt);
	SetFlag(eVObjVFixed);
}

Metric ActionButton::GetMinSize()
{
	if (TestFlag(eActionDefaultButton))
		return gLook->DefaultButtonLayout()->GetMinSize(this);
	return gLook->ActionButtonLayout()->GetMinSize(this);
}

void ActionButton::DrawInner(Rectangle, bool highlight)
{
	int code= 0;
	if (Enabled())
		SETBIT(code, 2);
	if (highlight)
		SETBIT(code, 3);
	if (TestFlag(eActionDefaultButton))
		gLook->DefaultButtonLayout()->Adorn(this, contentRect, code);
	else
		gLook->ActionButtonLayout()->Adorn(this, contentRect, code);
}

void ActionButton::Control(int id, int part, void *val)
{
	if (part == cPartToggle)
		part= cPartAction;
	Button::Control(id, part, val);
}

//---- StateButton -------------------------------------------------------------

NewAbstractMetaImpl(StateButton,Button, (T(state)));

StateButton::StateButton(int id, int s) : Button(id)
{
	state= s;
}

StateButton::StateButton(int id, const char *label, int s) : Button(id)
{
	state= s;
	if (label)
		Add(new TextItem(label));
}

StateButton::StateButton(int id, VObject *label, int s) : Button(id)
{
	state= s;
	if (label)
		Add(label);
}

void StateButton::DoTrackMouse(TrackPhase atp, Point pp)
{
	if (Enabled() && atp == eTrackRelease) {
		SetValue((int) !state);
		Control(GetId(), cPartToggle, (void*) state);
		Highlight(Off);
	} else
		Button::DoTrackMouse(atp, pp);
}

void StateButton::SetValue(int st, bool redraw)
{
	if (st != state) {
		state= st;
		Changed();
		if (redraw)
			ForceRedraw();
	}
}

int StateButton::GetValue()
{
	return state;
}

OStream& StateButton::PrintOn(OStream &s)
{
	Button::PrintOn(s);
	return s << state SP;
}

IStream& StateButton::ReadFrom(IStream &s)
{
	Button::ReadFrom(s);
	return s >> state;
}

//---- VObjectButton -----------------------------------------------------------

NewMetaImpl0(VObjectButton,StateButton);

VObjectButton::VObjectButton(int id, VObject *vop, int st) : StateButton(id, st)
{
	Add(vop);
}

Metric VObjectButton::GetMinSize()
{
	VObject *inner= At(0);
	Metric m= gLook->ActionButtonLayout()->GetMinSize(this);
	SetFlag(eVObjHFixed, inner->TestFlag(eVObjHFixed));
	SetFlag(eVObjVFixed, inner->TestFlag(eVObjVFixed));
	return m;
}

void VObjectButton::DrawInner(Rectangle, bool highlight)
{
	int code= 0;
	if (state)
		SETBIT(code, 1);
	if (Enabled())
		SETBIT(code, 2);
	if (highlight)
		SETBIT(code, 3);
	gLook->ActionButtonLayout()->Adorn(this, contentRect, code);
}

//---- RadioButton -------------------------------------------------------------

NewMetaImpl0(RadioButton,StateButton);

RadioButton::RadioButton(int id, bool st) : StateButton(id, st)
{
	SetFlag(eVObjVFixed|eVObjHFixed);
}

RadioButton::RadioButton(int id, const char *label, bool st)
											: StateButton(id, label, st)
{
	SetFlag(eVObjVFixed|eVObjHFixed);
}

RadioButton::RadioButton(int id, VObject *label, bool st)
												: StateButton(id, label, st)
{
	SetFlag(eVObjVFixed|eVObjHFixed);
}

Metric RadioButton::GetMinSize()
{
	return gLook->RadioButtonLayout()->GetMinSize(this);
}

void RadioButton::SetOrigin(Point at)
{
	VObject::SetOrigin(at);
	gLook->RadioButtonLayout()->SetOrigin(this, at);
}

void RadioButton::DrawInner(Rectangle, bool highlight)
{
	int code= 0;
	if (state)
		SETBIT(code, 1);
	if (Enabled())
		SETBIT(code, 2);
	if (highlight)
		SETBIT(code, 3);
	gLook->RadioButtonLayout()->Adorn(this, contentRect, code);
}

//---- ToggleButton ------------------------------------------------------------

NewMetaImpl0(ToggleButton,StateButton);

ToggleButton::ToggleButton(int id, bool st) : StateButton(id, st)
{
	SetFlag(eVObjVFixed|eVObjHFixed);
}

ToggleButton::ToggleButton(int id, const char *label, bool st)
												: StateButton(id, label, st)
{
	SetFlag(eVObjVFixed|eVObjHFixed);
}

ToggleButton::ToggleButton(int id, VObject *label, bool st)
												: StateButton(id, label, st)
{
	SetFlag(eVObjVFixed|eVObjHFixed);
}

Metric ToggleButton::GetMinSize()
{
	return gLook->ToggleButtonLayout()->GetMinSize(this);
}

void ToggleButton::SetOrigin(Point at)
{
	VObject::SetOrigin(at);
	gLook->ToggleButtonLayout()->SetOrigin(this, at);
}

void ToggleButton::DrawInner(Rectangle, bool highlight)
{
	int code= 0;
	if (state)
		SETBIT(code, 1);
	if (Enabled())
		SETBIT(code, 2);
	if (highlight)
		SETBIT(code, 3);
	gLook->ToggleButtonLayout()->Adorn(this, contentRect, code);
}

